﻿using System;
using System.ComponentModel;
using System.Drawing;
using ArtMath.Data.Converter;
using ArtMath.CommonType;
using ArtMath.Core.Data;
using ArtMath.Resource;

namespace ArtMath.Data
{
    [Serializable, TypeConverter(typeof(RPointSConverter))]
    public class RPointS : IStringSettable, IFormatPainter<RPointS>
    {
        PadStringX x, y;
        public event Action<PointD, PointD> CoordinateChanged;
        public RPointS(SketchPad pad, string x = null, string y = null)
        {
            X = new PadStringX(pad, x);
            Y = new PadStringX(pad, y);
        }
        public virtual PadStringX X
        {
            get { return x; }
            set
            {
                if (x is object)
                {
                    x.ParametersValueChanged -= XY_ParametersValueChanged;
                    x.ExpressionSet -= XY_ExpressionSet;
                }
                x = value;
                if (x is object)
                {
                    x.ParametersValueChanged += XY_ParametersValueChanged;
                    x.ExpressionSet += XY_ExpressionSet;
                }
            }
        }
        public virtual PadStringX Y
        {
            get { return y; }
            set
            {
                if (y is object)
                {
                    y.ParametersValueChanged -= XY_ParametersValueChanged;
                    y.ExpressionSet -= XY_ExpressionSet;
                }
                y = value;
                if (y is object)
                {
                    y.ParametersValueChanged += XY_ParametersValueChanged;
                    y.ExpressionSet += XY_ExpressionSet;
                }
            }
        }
        void XY_ParametersValueChanged(DocStringX sender, ParametersValueChangedEventArgs e)
        {
            xyEvent(sender, e.OldValue);
        }
        void XY_ExpressionSet(StringX sender, ExpressionSetEventArgs e)
        {
            xyEvent(sender, e.OldValue);
        }
        void xyEvent(StringX sender, double oldValue)
        {
            if (ReferenceEquals(sender, X))
            {
                CoordinateChanged?.Invoke(new PointD(oldValue, Y.Value), new PointD(sender.Value, Y.Value));
            }
            else
            {
                CoordinateChanged?.Invoke(new PointD(X.Value, oldValue), new PointD(X.Value, sender.Value));
            }
        }
        public void SetFromPointD(PointD pt)
        {
            SetSeparately(pt.X, pt.Y);
        }
        public virtual void SetSeparately(double x, double y)
        {
            X.SetExpression(x);
            Y.SetExpression(y);
        }
        public virtual void SetFromString(string exp)
        {
            string[] tokens = exp.Split(',', '，');
            if (tokens.Length == 2)
            {
                X.SetExpression(tokens[0].Trim());
                Y.SetExpression(tokens[1].Trim());
            }
            else
            {
                throw new ArgumentException(string.Format(Resources.Translate("AcceptNArgs"), Resources.Translate("NumberPair"), 2));
            }
        }
        public PointF ToPointF()
        {
            return new PointF(X.FloatValue, Y.FloatValue);
        }
        public PointD ToPointD()
        {
            return new PointD(X.Value, Y.Value);
        }
        public virtual PointD ToMathCoordinate()
        {
            return ToPointD();
        }
        public static PointD operator +(RPointS left, RPointS right)
        {
            return new PointD(left.X + right.X, left.Y + right.Y);
        }
        public static PointD operator -(RPointS left, RPointS right)
        {
            return new PointD(left.X - right.X, left.Y - right.Y);
        }
        public static PointD operator *(RPointS left, RPointS right)
        {
            return new PointD(left.X * right.X, left.Y * right.Y);
        }
        public static PointD operator /(RPointS left, RPointS right)
        {
            return new PointD(left.X / right.X, left.Y / right.Y);
        }
        public override string ToString()
        {
            return X.ToString() + ", " + Y.ToString();
        }

        public void UseFormat(RPointS obj)
        {
            SetFromPointD(X.LinkedPad.ConvertRPointS(obj, X.LinkedPad.OldCoordinate));
        }
    }
}
